<!DOCTYPE html>
<html>
<head>
    <title>Toroidal Coil Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            background-color: white;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="physicsCanvas" width="600" height="600"></canvas>

    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        /**
         * Draws an arrow from (x1, y1) to (x2, y2).
         * @param {CanvasRenderingContext2D} ctx - The rendering context.
         * @param {number} x1 - Start x-coordinate.
         * @param {number} y1 - Start y-coordinate.
         * @param {number} x2 - End x-coordinate.
         * @param {number} y2 - End y-coordinate.
         * @param {number} size - The length of the arrow head lines.
         */
        function drawArrow(ctx, x1, y1, x2, y2, size = 8) {
            const angle = Math.atan2(y2 - y1, x2 - x1);
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(x2, y2);
            ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
            ctx.moveTo(x2, y2);
            ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
            ctx.stroke();
        }

        /**
         * Draws a hatch pattern inside a rectangle.
         * @param {CanvasRenderingContext2D} ctx - The rendering context.
         * @param {number} x - The x-coordinate of the rectangle.
         * @param {number} y - The y-coordinate of the rectangle.
         * @param {number} w - The width of the rectangle.
         * @param {number} h - The height of the rectangle.
         * @param {number} spacing - The distance between hatch lines.
         */
        function hatchRect(ctx, x, y, w, h, spacing = 8) {
            ctx.save();
            ctx.beginPath();
            ctx.rect(x, y, w, h);
            ctx.clip();

            ctx.beginPath();
            ctx.strokeStyle = 'black';
            ctx.lineWidth = 0.8;
            for (let i = 0; i < (w + h); i += spacing) {
                ctx.moveTo(x + i, y);
                ctx.lineTo(x, y + i);
            }
            ctx.stroke();
            ctx.restore();
        }


        // --- Main Drawing Function ---
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = 'black';
            ctx.strokeStyle = 'black';
            ctx.lineWidth = 1;

            const cx = canvas.width / 2;

            // --- 1. Draw 3D Toroid ---
            const toroidTopY = 150;
            const R_outer = 140;
            const R_inner = 80;
            const H_toroid = 60;
            const Y_perspective = 0.3;
            const R_outer_y = R_outer * Y_perspective;
            const R_inner_y = R_inner * Y_perspective;

            // Draw solid body
            ctx.save();
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 1.5;

            // Main body color
            ctx.fillStyle = '#E0E0E0';
            
            // Draw outer wall
            ctx.beginPath();
            ctx.ellipse(cx, toroidTopY, R_outer, R_outer_y, 0, Math.PI, 0);
            ctx.lineTo(cx + R_outer, toroidTopY + H_toroid);
            ctx.ellipse(cx, toroidTopY + H_toroid, R_outer, R_outer_y, 0, 0, Math.PI, true);
            ctx.closePath();
            ctx.fill();
            ctx.stroke();

            // Draw inner hole (by filling with white and stroking)
            ctx.fillStyle = 'white';
            ctx.beginPath();
            ctx.ellipse(cx, toroidTopY, R_inner, R_inner_y, 0, Math.PI, 0);
            ctx.lineTo(cx + R_inner, toroidTopY + H_toroid);
            ctx.ellipse(cx, toroidTopY + H_toroid, R_inner, R_inner_y, 0, 0, Math.PI, true);
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
            
            // Draw top surface
            ctx.fillStyle = '#D3D3D3';
            ctx.beginPath();
            ctx.ellipse(cx, toroidTopY, R_outer, R_outer_y, 0, 0, 2 * Math.PI);
            ctx.ellipse(cx, toroidTopY, R_inner, R_inner_y, 0, 0, 2 * Math.PI, true);
            ctx.fill();
            ctx.stroke();
            ctx.restore();

            // Draw windings
            ctx.save();
            ctx.strokeStyle = '#222';
            ctx.lineWidth = 0.6;
            const num_windings = 48;
            for (let i = 0; i < num_windings; i++) {
                const angle = (i / num_windings) * 2 * Math.PI;
                const cos_a = Math.cos(angle);
                const sin_a = Math.sin(angle);

                const p_outer_top = { x: cx + R_outer * cos_a, y: toroidTopY + R_outer_y * sin_a };
                const p_inner_top = { x: cx + R_inner * cos_a, y: toroidTopY + R_inner_y * sin_a };
                const p_outer_bottom = { x: cx + R_outer * cos_a, y: toroidTopY + H_toroid + R_outer_y * sin_a };
                const p_inner_bottom = { x: cx + R_inner * cos_a, y: toroidTopY + H_toroid + R_inner_y * sin_a };

                // Top winding
                ctx.beginPath();
                ctx.moveTo(p_outer_top.x, p_outer_top.y);
                ctx.lineTo(p_inner_top.x, p_inner_top.y);
                ctx.stroke();

                // Outer surface winding
                ctx.beginPath();
                ctx.moveTo(p_outer_top.x, p_outer_top.y);
                ctx.lineTo(p_outer_bottom.x, p_outer_bottom.y);
                ctx.stroke();

                // Inner surface winding
                ctx.beginPath();
                ctx.moveTo(p_inner_top.x, p_inner_top.y);
                ctx.lineTo(p_inner_bottom.x, p_inner_bottom.y);
                ctx.stroke();
            }
            ctx.restore();

            // --- 2. Draw Central Axis ---
            ctx.save();
            ctx.lineWidth = 1;
            ctx.strokeStyle = 'black';
            ctx.setLineDash([8, 3, 2, 3]); // Dash-dot pattern
            ctx.beginPath();
            ctx.moveTo(cx, 50);
            ctx.lineTo(cx, 500);
            ctx.stroke();
            ctx.restore();

            // --- 3. Draw Cross Section ---
            const crossSectionY = 400;
            const R1 = 70;
            const R2 = 130;
            const h = 50;

            // Draw rectangles
            ctx.lineWidth = 1.5;
            const rect_w = R2 - R1;
            const rect_h = h;
            const left_rect_x = cx - R2;
            const right_rect_x = cx + R1;
            const rect_y = crossSectionY - h / 2;
            
            ctx.strokeRect(left_rect_x, rect_y, rect_w, rect_h);
            ctx.strokeRect(right_rect_x, rect_y, rect_w, rect_h);

            // Hatch fill rectangles
            hatchRect(ctx, left_rect_x, rect_y, rect_w, rect_h);
            hatchRect(ctx, right_rect_x, rect_y, rect_w, rect_h);

            // Draw dimension lines and labels
            ctx.lineWidth = 1;
            ctx.font = "italic 16px Times New Roman";
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            
            // Dimension for h
            const h_dim_x = cx + R2 + 25;
            drawArrow(ctx, h_dim_x, rect_y, h_dim_x, rect_y + h);
            ctx.fillText('h', h_dim_x + 12, crossSectionY);

            // Dimension for R1
            const r1_dim_y = rect_y + h + 20;
            drawArrow(ctx, cx, r1_dim_y, cx + R1, r1_dim_y);
            ctx.fillText('R', cx + R1 / 2 - 5, r1_dim_y + 8);
            ctx.font = "italic 12px Times New Roman";
            ctx.fillText('1', cx + R1 / 2 + 2, r1_dim_y + 11);
            
            // Dimension for R2
            ctx.font = "italic 16px Times New Roman";
            const r2_dim_y = rect_y + h + 40;
            drawArrow(ctx, cx, r2_dim_y, cx - R2, r2_dim_y);
            ctx.fillText('R', cx - R2 / 2 - 5, r2_dim_y + 8);
            ctx.font = "italic 12px Times New Roman";
            ctx.fillText('2', cx - R2 / 2 + 2, r2_dim_y + 11);

            // --- 4. Draw Title ---
            ctx.fillStyle = 'black';
            ctx.font = "18px SimHei";
            ctx.textAlign = 'center';
            ctx.textBaseline = 'bottom';
            ctx.fillText("习题 9-20 图", cx, 570);
        }

        draw();
    </script>
</body>
</html>